package com.haibara.aiojjudgeservice.service.impl;

import cn.hutool.json.JSONUtil;
import com.haibara.aiojfeignclient.client.QuestionClient;
import com.haibara.aiojjudgeservice.codesandbox.CodeSandbox;
import com.haibara.aiojjudgeservice.codesandbox.factory.CodeSandboxFactory;
import com.haibara.aiojjudgeservice.codesandbox.proxy.CodeSandboxProxy;
import com.haibara.aiojjudgeservice.service.JudgeService;
import com.haibara.aiojjudgeservice.strategy.JudgeContext;
import com.haibara.aiojjudgeservice.strategy.JudgeManager;
import com.haibara.aiojmodel.model.codesandbox.ExecuteCodeRequest;
import com.haibara.aiojmodel.model.codesandbox.ExecuteCodeRespond;
import com.haibara.aiojmodel.model.dto.question.JudgeCase;
import com.haibara.aiojmodel.model.dto.question.JudgeConfig;
import com.haibara.aiojmodel.model.dto.questionsubmit.JudgeInfo;
import com.haibara.aiojmodel.model.entity.Question;
import com.haibara.aiojmodel.model.entity.QuestionSubmit;
import com.haibara.aiojmodel.model.enums.JudgeInfoMessageEnum;
import com.haibara.aiojmodel.model.enums.QuestionSubmitLanguageEnum;
import com.haibara.aiojmodel.model.enums.QuestionSubmitStatusEnum;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Service
public class JudgeServiceImpl implements JudgeService {

//    @Resource
//    private QuestionService questionService;
//    @Resource
//    private QuestionSubmitService questionSubmitService;
    @Resource
    private QuestionClient questionClient;

    @Resource
    private JudgeManager judgeManager;

    @Value("${codesandbox.type}")
    private String type;

    @Override
    public QuestionSubmit doJudge(Long questionSubmitId) {
        // 1.传入题目提交id，获取到对应题目、提交信息
        QuestionSubmit questionSubmit = questionClient.getQuestionSubmitById(questionSubmitId);
        Long questionId = questionSubmit.getQuestionId();
        Question question = questionClient.getQuestionById(questionId);
        // 2.若题目状态不为等待中，就不重复执行 （幂等性）
        if(!Objects.equals(questionSubmit.getStatus(), QuestionSubmitStatusEnum.WAITING.getValue())){
            return null;
        }
        // 3.修改判题状态为判题中，防止重复执行
        questionSubmit.setStatus(QuestionSubmitStatusEnum.RUNNING.getValue());
        questionClient.updateQuestionSubmit(questionSubmit);
        // 4.调用沙箱，执行代码
        CodeSandboxFactory codeSandboxFactory = new CodeSandboxFactory();
        CodeSandbox codeSandbox = new CodeSandboxProxy(codeSandboxFactory.getCodeSandbox(type));

        String judgeCaseStr = question.getJudgeCase();
        List<JudgeCase> judgeCaseList = JSONUtil.toList(judgeCaseStr,JudgeCase.class);
        String language = questionSubmit.getLanguage();
        String code = questionSubmit.getCode();
        List<String> inputList = judgeCaseList.stream().map(JudgeCase::getInput).collect(Collectors.toList());
        ExecuteCodeRequest ecr = ExecuteCodeRequest.builder()
                .inputList(inputList)
                .code(code)
                .questionId(questionId)
                .language(QuestionSubmitLanguageEnum.getEnumByValue(language))
                .build();
        ExecuteCodeRespond executeCodeRespond = codeSandbox.executeCode(ecr);
        if(executeCodeRespond.getStatus() == ExecuteCodeRespond.ERROR){
            questionSubmit = new QuestionSubmit();
            questionSubmit.setId(questionSubmitId);
            questionSubmit.setStatus(QuestionSubmitStatusEnum.FAILED.getValue());
            JudgeInfo judgeInfo = new JudgeInfo();
            // 设置相关信息
            judgeInfo.setMessage(executeCodeRespond.getMessage());
            JudgeConfig judgeConfig = JSONUtil.toBean(question.getJudgeConfig(),JudgeConfig.class);
            judgeInfo.setMemory(Double.valueOf(judgeConfig.getMemoryLimit()));
            judgeInfo.setTime(judgeConfig.getTimeLimit());
            questionSubmit.setJudgeInfo(JSONUtil.toJsonStr(judgeInfo));
            boolean b = questionClient.updateQuestionSubmit(questionSubmit);
            return questionSubmit;
        }

        JudgeContext judgeContext = new JudgeContext();
        judgeContext.setInputList(inputList);
        judgeContext.setOutputList(executeCodeRespond.getOutputList());
        judgeContext.setJudgeInfo(executeCodeRespond.getJudgeInfo());
        judgeContext.setQuestion(question);
        judgeContext.setJudgeCaseList(judgeCaseList);
        judgeContext.setQuestionSubmit(questionSubmit);

        JudgeInfo judgeInfo = judgeManager.doJudge(judgeContext);

        // 修改数据库中的判题结果
        questionSubmit = new QuestionSubmit();
        questionSubmit.setId(questionSubmitId);
        questionSubmit.setStatus(QuestionSubmitStatusEnum.SUCCEED.getValue());
        questionSubmit.setJudgeInfo(JSONUtil.toJsonStr(judgeInfo));
        boolean b = questionClient.updateQuestionSubmit(questionSubmit);
        if(JudgeInfoMessageEnum.ACCEPTED.getValue().equals(judgeInfo.getMessage())){
            question.setAcceptedNum(question.getAcceptedNum()+1);
            questionClient.updateQuestion(question);
        }
        return questionSubmit;
    }
}
